package com.xdhl.fu.order.consumer;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xdhl.fu.common.core.constant.event.reservation.ReservationConstants;
import com.xdhl.fu.common.redis.service.RedisService;
import com.xdhl.fu.flight.info.api.RemoteFlightInfoService;
import com.xdhl.fu.flight.info.api.mongodb.domain.MGFlightSchedule;
import com.xdhl.fu.flight.info.api.mongodb.domain.MGReservation;
import com.xdhl.fu.order.domain.OrderInfo;
import com.xdhl.fu.order.domain.OrderPassenger;
import com.xdhl.fu.order.repository.MGReservationRepository;
import com.xdhl.fu.order.service.IOrderInfoService;
import com.xdhl.fu.order.service.IOrderPassengerService;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 创建订单事件消费者
 *
 * @author 朱力维
 * @time 2022/6/12 20:59
 */
@Component
/**
 *
 *
 * @author 朱力维
 * @time 2022/7/11 15:27
 **/
public class CreateOrderEventConsumer {

    private static final Logger log = LoggerFactory.getLogger(CreateOrderEventConsumer.class);

    @Value("#{'${spring.application.name}'+'-'+'${spring.profiles.active}'}")
    private String consumerGroup;

    @Value("${fu.rocketmq.namesrv-addr}")
    private String namesrvAddr;

    private DefaultMQPushConsumer consumer;

    @Resource
    private RedisService redisService;

    @Resource
    private IOrderPassengerService orderPassengerService;

    @Resource
    private IOrderInfoService orderInfoService;

    @Resource
    private RemoteFlightInfoService remoteFlightInfoService;

    @Resource
    private MGReservationRepository mgReservationRepository;

    @PostConstruct
    public void init() throws MQClientException {
        consumer = new DefaultMQPushConsumer(consumerGroup);
        consumer.setNamesrvAddr(namesrvAddr);

        //设置consumer所订阅的Topic和Tag，*代表全部的Tag
        consumer.subscribe(ReservationConstants.RESERVATION_ORDER_CREATE, "*");

        /**
         * CONSUME_FROM_LAST_OFFSET 默认策略，从该队列最尾开始消费，跳过历史消息
         * CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费，即历史消息（还储存在broker的）全部消费一遍
         */
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);

        consumer.registerMessageListener((MessageListenerConcurrently) (list, context) -> doing(list));
        consumer.start();
        log.info("订单创建事件订单消费者启动成功。");
    }


    @PreDestroy
    public void destory() {
        consumer.shutdown();
        log.info("订单创建事件订单消费者已销毁。");
    }

    @Transactional
    public ConsumeConcurrentlyStatus doing(List<MessageExt> msgs) {
        ConsumeConcurrentlyStatus consumeConcurrentlyStatus;
        try {
            for (MessageExt msg : msgs) {
                JSONObject data = JSONObject.parseObject(new String(msg.getBody(), RemotingHelper.DEFAULT_CHARSET));
                String dataId = data.getString("dataId");
                String orderSerialNumber = data.getString("orderSerialNumber");

                MGReservation mgReservation = mgReservationRepository.findById(dataId).get();

                JSONArray passengers = mgReservation.getPassengers();

                JSONObject member = mgReservation.getMember();

                MGFlightSchedule flightSchedule = mgReservation.getFlightSchedule();

                String memberDataId = member.getString("dataId");

                // 创建订单
                OrderInfo orderInfo = new OrderInfo();
                orderInfo.setFlightDataId(flightSchedule.getFlightInfo().getDataId());
                Double price = 0D;
                for (Object obj : passengers) {
                    JSONObject passenger = JSONObject.parseObject(JSONObject.toJSONString(obj));
                    String flightClass = passenger.getString("flightClass");
                    switch (flightClass) {
                        case "A":
                            price += flightSchedule.getFlightSchedule().getHeadPrice();
                            passenger.put("price", flightSchedule.getFlightSchedule().getHeadPrice());
                            break;
                        case "B":
                            price += flightSchedule.getFlightSchedule().getBusinessPrice();
                            passenger.put("price", flightSchedule.getFlightSchedule().getBusinessPrice());
                            break;
                        case "C":
                            price += flightSchedule.getFlightSchedule().getEconomyPrice();
                            passenger.put("price", flightSchedule.getFlightSchedule().getEconomyPrice());
                            break;
                    }
                    // 机建燃油费 TODO 待优化
                    price += 50D;
                }
                orderInfo.setPrice(price);
                orderInfo.setMemberDataId(memberDataId);
                orderInfo.setOStatus("A");
                orderInfo.setChangeStatus("A");
                orderInfo.setChargebackStatus("A");
                orderInfo.setCreateBy(memberDataId);
                orderInfo.setCreateTime(LocalDateTime.now());
                orderInfo.setUpdateBy(memberDataId);
                orderInfo.setUpdateTime(LocalDateTime.now());
                orderInfo.setSerialNumber(orderSerialNumber);
                orderInfoService.save(orderInfo);
                mgReservation.setOrder(JSONObject.parseObject(JSONObject.toJSONString(orderInfo)));
                // 保存旅客和订单关系
                JSONArray passengersNew = new JSONArray();
                for (Object obj : passengers) {
                    JSONObject passenger = JSONObject.parseObject(JSONObject.toJSONString(obj));
                    OrderPassenger orderPassenger = new OrderPassenger();
                    orderPassenger.setOrderDataId(orderInfo.getDataId());
                    orderPassenger.setPassengerDataId(passenger.getString("dataId"));
                    orderPassenger.setFlightClass(passenger.getString("flightClass"));
                    switch (passenger.getString("flightClass")) {
                        case "A":
                            orderPassenger.setPrice(flightSchedule.getFlightSchedule().getHeadPrice());
                            break;
                        case "B":
                            orderPassenger.setPrice(flightSchedule.getFlightSchedule().getBusinessPrice());
                            break;
                        case "C":
                            orderPassenger.setPrice(flightSchedule.getFlightSchedule().getEconomyPrice());
                            break;
                    }
                    orderPassenger.setTaxation(50D);
                    orderPassenger.setCreateBy(memberDataId);
                    orderPassenger.setCreateTime(LocalDateTime.now());
                    orderPassenger.setUpdateBy(memberDataId);
                    orderPassenger.setUpdateTime(LocalDateTime.now());
                    orderPassengerService.save(orderPassenger);
                    passengersNew.add(JSONObject.parseObject(JSONObject.toJSONString(orderPassenger)));
                }

                mgReservation.setPassengers(passengersNew);
                mgReservationRepository.save(mgReservation);

                // 将订单放入缓存，等待付款
                redisService.setCacheObject("order_waiting_pay:" + dataId, dataId, 15L, TimeUnit.MINUTES);
            }
            consumeConcurrentlyStatus = ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        } catch (Exception e) {
            log.error(e.getMessage());
            consumeConcurrentlyStatus = ConsumeConcurrentlyStatus.RECONSUME_LATER;
            // nothing to do.
        }
        return consumeConcurrentlyStatus;
    }

}
